package com.hitechbangla.fctu.base.aircraft;

import com.hitechbangla.fctu.base.aircraft.command.AircraftCommandState;
import com.hitechbangla.fctu.utility.enumall.CommandType;
import com.hitechbangla.fctu.utility.enumall.*;
import com.hitechbangla.fctu.base.aircraft.command.AircraftTurnCommand;
import com.hitechbangla.fctu.base.weather.Wind;
import com.hitechbangla.fctu.base.weather.WindLayer;
import com.hitechbangla.fctu.utility.AircraftUtility;
import com.hitechbangla.fctu.utility.Const;
import com.hitechbangla.fctu.utility.GeneralUtil;
import fctu.simulator.HTB_MAIN;
import java.awt.Graphics;
import java.io.Serializable;

/*
 *
 * @author deb kanti
 *
 */
public class Aircraft implements Serializable 
{
    private AircraftState aircraftState;
    private AircraftType aircraftType;
    private AircraftCommandState aircraftCommandState;
    private AircraftTurnCommand aircraftTurnCommand;
    private AIRadar aIRadar;
    private Wind wind;
    //private String groupName;
    private double heightStatus;
    private final float fuelConsumtionRate = 0.1f;
    private boolean iffSignalCheck;
    
    public Aircraft()
    {
        
    }
    
    public Aircraft(AircraftState aircraftState,AircraftType aircraftType)
    {
        this.aircraftState = aircraftState;
        this.aircraftType = aircraftType;
        this.aircraftCommandState = null;
        this.aircraftTurnCommand = null;
        this.iffSignalCheck = false;
	//this.aIRadar = new AIRadar(this, 50, 60);
	//this.wind = HTB_MAIN.gameScene.windList.get(0);
	//this.wind = Wind.getAllWind().get(0);
	this.heightStatus = this.getAircraftState().getLocation().getZ();
    } // end of constructor
    
    public void executeCommand(String rawCommand)
    {
        setAircraftCommandState(new AircraftCommandState(rawCommand,this));
        getAircraftCommandState().executeCommand();
    } // end of executeCommand command

    /**
     * @return the aircraftState
     */
    public AircraftState getAircraftState() 
    {
        return aircraftState;
    }
    

    /**
     * @return the aircraftType
     */
    public AircraftType getAircraftType() 
    {
        return aircraftType;
    }
    
    
    /**
     * @return the aircraftCommandState
     */
    public AircraftCommandState getAircraftCommandState() 
    {
        return aircraftCommandState;
    }   

    /**
     * @param aircraftCommandState the aircraftCommandState to set
     */
    public void setAircraftCommandState(AircraftCommandState aircraftCommandState) 
    {
        this.aircraftCommandState = aircraftCommandState;
    }
    
    // update the location of the aircraft after getting command
    
    public void addAIRadar(AIRadar aIRadar)
    {
	this.setaIRadar(aIRadar);
	aIRadar.setOwnerAircraft(this);
    } // end of addAIRadar method
    
    public void update(float timeInterval) 
    {	
	if(aircraftCommandState!=null)
	{
	    if(aircraftCommandState.getCommandStatus() == CommandStatus.TURN)
	    {
		if(aircraftCommandState.getCommandType() == CommandType.Type1 )
		{
		    AircraftState nextAircraftState = new AircraftState(); // this object contains only the heading
                //float angleIncrement = 
                
		    float headingNew = (Const.THREE_SIXTY_DEGREE + aircraftTurnCommand.getAngleIncrement()+aircraftState.getHeading())%360;	    
		    
		    nextAircraftState.setHeading(headingNew);  


		    boolean inBetween = AircraftUtility.isAngleBetweenCurrentAndTarget(getAircraftState().getHeading(), nextAircraftState.getHeading(), getAircraftCommandState().getHeadingAngle(), getAircraftCommandState().getTurnDirection());
		    

		    if(inBetween)
		    {
			aircraftState.setHeading(headingNew);
			continueWithCurrent(nextAircraftState);
		    }
		    else
		    {
			float remainingAngle, remainingTime;

			if(aircraftCommandState.getTurnDirection() == TurnDirection.RIGHT)
			{
			    remainingAngle = (Const.THREE_SIXTY_DEGREE + getAircraftCommandState().getHeadingAngle() - aircraftState.getHeading())%Const.THREE_SIXTY_DEGREE;                    
			}   
			else
			{
			    remainingAngle = (Const.THREE_SIXTY_DEGREE +  aircraftState.getHeading() - getAircraftCommandState().getHeadingAngle())%Const.THREE_SIXTY_DEGREE;                    
			}

			remainingTime = (timeInterval - (remainingAngle/aircraftTurnCommand.getAngleIncrement()))/1000 ;
			aircraftState.setHeading(getAircraftCommandState().getHeadingAngle());
			followPathInCurrentHeading(remainingTime);

			aircraftCommandState = null;
			aircraftTurnCommand = null;
		    }
		    
		}
		else if (aircraftCommandState.getCommandType() == CommandType.Type6) // orbit command
		{
		    AircraftState nextAircraftState = new AircraftState(); // this object contains only the heading             
                
		    nextAircraftState.setHeading((Const.THREE_SIXTY_DEGREE + getAircraftState().getHeading() + GeneralUtil.radianToDegree(aircraftTurnCommand.getAngleIncrement()))%Const.THREE_SIXTY_DEGREE);
		    continueWithCurrent(nextAircraftState);
		}
		
		else if (aircraftCommandState.getCommandType() == CommandType.Type4) // rollout command
		{
		    continueStraight();
		}
		
		
	    }        

	    else if (aircraftCommandState.getCommandStatus() == CommandStatus.HEIGHT_CHANGE)
	    {		
		double nextHeight = aircraftState.getLocation().getZ() + aircraftCommandState.getClimbRate() * aircraftCommandState.getExpedite(); ;

		if(heightCloser(nextHeight, aircraftCommandState.getAircraftHeightTarget()))
		{
                    if(heightStatus>=0)
                    {  
                    
                        aircraftState.getLocation().setZ(aircraftCommandState.getAircraftHeightTarget());

                        // now we have to add the wind component here
                        //float heightStatus = this.getWind().getLayerIndexOnHeight(getHeightStatus());
                        int layerIndex = this.getWind().getLayerIndexOnHeight(this.getAircraftState().getLocation().getZ()); 

                        int layerIndexOnStatus = this.getWind().getLayerIndexOnHeight(getHeightStatus());

                        if(layerIndexOnStatus != layerIndex)
                        {
                            this.setHeightStatus(this.getAircraftState().getLocation().getZ());
                            // updating the x,y component for wind
                            WindLayer windLayer = this.wind.getLayer(layerIndex);

                            this.aircraftState.getLocation().setX(this.aircraftState.getLocation().getX() + GeneralUtil.getVectorX(windLayer.getWindSpeed(), windLayer.getWindHeading()));
                            this.aircraftState.getLocation().setY(this.aircraftState.getLocation().getY() + GeneralUtil.getVectorY(windLayer.getWindSpeed(), windLayer.getWindHeading()));
                            // 
                        } // end if    
                    }
		    
		    
		    
		}         
		else
		{
                    if(nextHeight>=0)
                    {
                        aircraftState.getLocation().setZ(nextHeight);
                    }
                    //aircraftTurnCommand = null;
                    continueStraight();
                    //System.out.println("from aircraft: jsdkfasdjfkas");
		} // end else            
	    }
            
            else if(aircraftCommandState.getCommandStatus() == CommandStatus.SPEED_CHANGE)
            {
                aircraftState.setSpeed(aircraftCommandState.getSpeedNew());
                continueStraight();
            }
	}
	else
        {
            continueStraight();
        } 
	// update of new aircraft location ended 
	
	this.getAircraftState().setFuelStatus(this.getAircraftState().getFuelStatus() - fuelConsumtionRate);
        
	/*
	if(getaIRadar() != null)
        {
	    getaIRadar().update();
	}
	*/
	//aircraftState.getListLocation().add(aircraftState.getLocation());
       
    } // end of update function
    
    private void continueWithCurrent(AircraftState nextAircraftState)
    {	
	
	double cosValue = (float)Math.cos(GeneralUtil.degreeToRadian(nextAircraftState.getHeading()));
	double sinValue = (float)Math.sin(GeneralUtil.degreeToRadian(nextAircraftState.getHeading()));
	
	double changeX = aircraftTurnCommand.getArcLength() * sinValue;
	double changeY = aircraftTurnCommand.getArcLength() * cosValue;	
	
	double positionX = aircraftState.getLocation().getX() + changeX ;
	double positionY = aircraftState.getLocation().getY() + changeY ;
	
	aircraftState.getLocation().setX(positionX);
	aircraftState.getLocation().setY(positionY);	
    }
    
    
    private boolean heightCloser(double nextHeight, double target)
    {
        if(aircraftCommandState.getAircraftHeightChangeType() == AircraftHeightChangeType.CLIMB)
        {
            if(nextHeight>target)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else if(aircraftCommandState.getAircraftHeightChangeType() == AircraftHeightChangeType.DESCEND)
        {
            if(nextHeight < target)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    
    
    public void executeCommand()
    {
        if(aircraftCommandState.getCommandStatus() == CommandStatus.TURN) // checks if the current command is turn command
        {
            aircraftTurnCommand = new AircraftTurnCommand(this);
            aircraftTurnCommand.executeCommand();
        }
        else if(aircraftCommandState.getCommandStatus() == CommandStatus.HEIGHT_CHANGE)
        {
            
        }
        else if(aircraftCommandState.getCommandStatus() == CommandStatus.SPEED_CHANGE)
        {
	    
        }        
    }
    
    
    /*
    private boolean checkIfTurnCommand(AircraftCommandState aircraftCommandState)
    {
            if(aircraftCommandState.getCommandType() == CommandType.Type1)
            {
                return true;
            }
            
            else if(aircraftCommandState.getCommandType() == CommandType.Type2)
            {
                return true;
            }
            else if(aircraftCommandState.getCommandType() == CommandType.Type3)
            {
                return true;
            }
            else if(aircraftCommandState.getCommandType() == CommandType.Type4)
            {
                return true;
            }
            else if(aircraftCommandState.getCommandType() == CommandType.Type5)
            {
                return true;
            }
            else if(aircraftCommandState.getCommandType() == CommandType.Type6)
            {
                return true;
            }
            else
            {
                return false;
            }
    }
    */

    private void followPathInCurrentHeading(float remainingTime) 
    {
        float normalizeSpeedInNmPerSec = aircraftState.getSpeed() / 3600;
        float angle = GeneralUtil.degreeToRadian((450.0f-aircraftState.getHeading()%360.0f));
        
        AircraftState nextAircraftState = new AircraftState();
        nextAircraftState.getLocation().setX(aircraftState.getLocation().getX() + normalizeSpeedInNmPerSec * (float)Math.cos(angle)*remainingTime);
        nextAircraftState.getLocation().setY(aircraftState.getLocation().getY() + normalizeSpeedInNmPerSec * (float)Math.sin(angle)*remainingTime);
        
        aircraftState.getLocation().setX(nextAircraftState.getLocation().getX());
        aircraftState.getLocation().setY(nextAircraftState.getLocation().getY());
    }
    
    public void draw(Graphics g)
    {
	//getaIRadar().draw(g);
	////System.out.println("Okay");
    }
    

    /**
     * @return the aIRadar
     */
    public AIRadar getaIRadar() {
        return aIRadar;
    }

    /**
     * @param aIRadar the aIRadar to set
     */
    public void setaIRadar(AIRadar aIRadar) {
        this.aIRadar = aIRadar;
    }

    /*
    private boolean checkIfHeightChangeCommand() 
    {
        if(aircraftCommandState.getCommandType() == CommandType.Type7)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    private boolean checkIfSpeedChangeCommand() 
    {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    */

    /**
     * @return the wind
     */
    public Wind getWind() {
	return wind;
    }

    /**
     * @param wind the wind to set
     */
    public void setWind(Wind wind) {
	this.wind = wind;
    }

    /**
     * @return the heightStatus
     */
    public double getHeightStatus() {
	return heightStatus;
    }

    /**
     * @param heightStatus the heightStatus to set
     */
    public void setHeightStatus(double heightStatus) {
	this.heightStatus = heightStatus;
    }

    private void continueStraight() 
    {
	float speedNMperSec = getAircraftState().getSpeed()/3600;            
            
        double tempLocationX = speedNMperSec*(double)Math.sin(GeneralUtil.degreeToRadian(getAircraftState().getHeading())) + aircraftState.getLocation().getX();
        double tempLocationY = speedNMperSec*(double)Math.cos(GeneralUtil.degreeToRadian(getAircraftState().getHeading())) + aircraftState.getLocation().getY();;
            
        aircraftState.getLocation().setX(tempLocationX);
        aircraftState.getLocation().setY(tempLocationY);   	    
    }
    
    private EcmType ecmType;

    public EcmType getEcmType() {
	return ecmType;
    }

    public void setEcmType(EcmType ecmType) {
	this.ecmType = ecmType;
    }

    /**
     * @return the iffSignalCheck
     */
    public boolean isIffSignalCheck() {
        return iffSignalCheck;
    }

    /**
     * @param iffSignalCheck the iffSignalCheck to set
     */
    public void setIffSignalCheck(boolean iffSignalCheck) {
        this.iffSignalCheck = iffSignalCheck;
    }
    
}